#pragma once

class ADTChunk
{
	ui32 m_chunkSize;
	ui32 m_baseOffset;
	CMpqFile* m_pFile;
	ADTModel* m_pParent;
	MCNKHDR m_header;
	Mesh m_mesh;
	float xbase, ybase, zbase;
	static float m_texcoords[145][2];
	static float m_alphaCoords[145][2];
	static IDirect3DTexture9* m_sIdTexture;
	Texture* m_texture;
	Texture* m_blendTexture[3];
	ui8 m_alpha[4096][4];
	float m_alphaf[4096][4];
	IDirect3DTexture9* m_alphaTex[3];
	IDirect3DTexture9* m_shadowTex;
	IDirect3DTexture9* m_holeTexture;
	static ID3DXEffect* m_blendEffect[4];
	static bool m_initEffects;
	bool m_loaded;
	Vertex3FCNT2 rlVertices[145];
	FileBuffer* m_parentBuffer;
	bool m_animate;
	ui32 m_lastRender;
	std::vector<TileTexLayer> m_textureLayers;
	i32 AddTexture(ui32 texLevel, Texture* pTexture, ui32 flags);
	void RecalcOffsets(ui32 pos, i32 change);
	void AddTextureLayer(std::string szTexture);
	bool m_locked;
	ui32 m_mccv[145];
	void LoadShadows();
	void LoadAlpha();
	void LoadAlphaSelfCompress(ui32 index, ui32 offset);
	void LoadAlphaUncompress(ui32 index, ui32 offset);
	void CreateUncompressedAlpha(ui32 alphaLayer);
	ui32 m_layerSizeCompr[3];
	void AddTextureLayerNew(std::string szTexture);
	void LoadHoles();
	void ReloadShadows();
	void Load();
	void InitStatics();
	void LoadVertices();
	void LoadNormals();
	void LoadMCCV();
	void ReloadNormals();

	std::set<ui32> m_objectRefs;

	Vertex3F m_normals[145];

	ui8 m_shadowMap[4096][4];
	Vertex3F mPosMin, mPosMax;
	bool mChangeNormals;
	ui32 mLastNormalChange;
	ADTChunkRender mRenderer;

	Mutex m_renderLock;
public:
	ADTChunk(ui32 offset, CMpqFile* pFile, ADTModel* pParent, FileBuffer* buffer, bool initial = false);
	void Draw(Vertex3F position, Vertex3F tar);

	__declspec(nothrow)	void SetBaseOffset(ui32 baseOffset) { m_baseOffset = baseOffset; }
	NOINLINE void Deinit();
	__declspec(nothrow) MCNKHDR& GetHeader() { return m_header; }
	void NormalizeAlphas();
	TileTexLayer& GetTexLayer(ui32 index) { if(index >= m_textureLayers.size()) throw "Out of range!"; return m_textureLayers[index]; }
	bool Intersect(D3DXVECTOR3& rayO, D3DXVECTOR3& rayDir, float* pOut);

	std::vector<std::string> GetTextures();

	__declspec(nothrow) bool GetLock() { return m_locked; }

	void BeforeReset();
	void OnReset();

	ADTChunkLoader& getChunkLoader();

	ui32 GetAreaId() { return m_header.areaId; }
	void SetAreaId(ui32 id) { m_header.areaId = id; }
	void Save();

	std::string GetTextureName(ui32 index);

	void ChangeHeight(Vertex3F midPoint, float radius, float amount, ui32 type);
	void FlattenHeight(Vertex3F midPoint, float radius, float amount, ui32 type);
	void BlurHeight(Vertex3F midPoint, float radius, float amount, ui32 type);
	float GetLandHeight(float x, float z);
	bool getLandHeightFast(float x, float z, float& h);

	void ChangeTexture(Vertex3F midPoint, float radius, float amount, ui32 type, Texture* tex, ui32 brushType);
	ADTModel* GetParent() { return m_pParent; }

	void ToggleLock() { m_locked = !m_locked; }

	void DrawMCCV(ui8 facAlpha, ui8 facRed, ui8 facGreen, ui8 facBlue, Vertex3F point, float radius);

	void ToggleHole(Vertex3F pos);
	void DrawShadow(Vertex3F pos, float radius, bool on);

	void UpdateMDXPosition(ADTModel* pBaseMap, ui32 doodad, float x, float y, float z);
	void Update(ui32 diff);
	void RedoNormals() { ReloadNormals(); }

	bool isGraphicsLoaded() const;

	IDirect3DTexture9* getAlphaTexture() { return m_alphaTex[0]; }

	static ui16 triangleIndices[64][12];
};